import 'reflect-metadata'

// 类装饰器
// 参数: 类本身
function classDecorator(target) {
  // console.log(target)
}

// 参数装饰器
// 参数装饰器在类的静态方法上使用时 接收 3 个参数: 类 方法名 参数索引从左往右从0开始
// 参数装饰器在类的原型方法上使用时 接收 3 个参数: 类的原型 方法名 参数索引从左往右从0开始
function paramDecorator(target, propertyKey, parameterIndex) {
  // console.log(target, propertyKey, parameterIndex)
}

// 属性装饰器
// 如果属性装饰器装饰的是类中的静态属性 接收 2 个参数: 类 属性名
// 如果属性装饰器装饰的是类中的实例属性 接收 2 个参数: 类的原型 属性名
function propDecorator(target, propertyKey) {
  // console.log(target, propertyKey)
}

// 方法装饰器
// 如果方法装饰器 装饰的是类中的方法 接收 3 个参数: 类的原型对象 被装饰的方法名 属性描述符
// 如果方法装饰器 装饰的是类中的静态方法 接收 3 个参数: 类 被装饰的方法名 属性描述符
function methodDecorator(target, propertyKey, descriptor) {
  // console.log(target, propertyKey, descriptor)
}

@classDecorator
class ExampleClass {
  @propDecorator
  myProperty: string

  constructor(@paramDecorator serviceA: string, @paramDecorator serviceB: number) {
    console.log('ExampleClass constructor')
  }

  @methodDecorator
  static myMethod(a: number, b: boolean): string {
    return 'hello'
  }
}

// typescript 自动给 myProperty属性添加 design:type 元数据
// design:type 用于属性的类型元数据
const propertyType = Reflect.getMetadata('design:type', ExampleClass.prototype, 'myProperty')
console.log(propertyType, propertyType === String) // [Function: String] true

// typescript 自动给 ExampleClass 构造函数添加 design:paramtypes 元数据
// design:paramtypes 用于构造函数或方法 获取参数的类型组成的数组
const paramTypes = Reflect.getMetadata('design:paramtypes', ExampleClass)
console.log(paramTypes) // [ [Function: String], [Function: Number] ]

// typescript 自动给 ExampleCalss 中的方法添加 design:paramtypes 元数据
// design:paramtypes 用于构造函数或方法 获取参数的类型组成的数组
const paramTypes2 = Reflect.getMetadata('design:paramtypes', ExampleClass, 'myMethod')
console.log(paramTypes2) // [ [Function: Number], [Function: Boolean] ]

// typescript 自动给 ExampleClass 中的方法添加 design:returntypes 元数据
// design:returntype 用于构造函数或方法 获取参数的类型组成的数组
const returnType = Reflect.getMetadata('design:returntype', ExampleClass, 'myMethod')
console.log(returnType) // [Function: String]

// design:type 用于属性的类型元数据
// design:paramtypes 用于构造函数或方法参数的类型元数据
// design:returntype 用于方法的返回类型元素
const paramType3 = Reflect.getMetadata('design:type', ExampleClass, 'myMethod')
console.log(paramType3, paramType3 === Function) // [Function: Function] true